package org.bingo.service;

import org.bingo.entity.VideoEntity;
import org.bingo.entity.VideoIndex;
import org.bingo.misc.MinioUtil;
import org.bingo.misc.VideoUtil;
import org.bingo.repository.VideoEntityRepository;
import org.bingo.repository.VideoIndexRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;

@Service
public class FileService {

    @Autowired
    private MinioUtil minioUtil;

    @Value("F:\\uploaded")
    private String uploadTmp;

    @Value("${minio.avatar-bucket}")
    private String avatarBucket;

    @Value("${minio.video-bucket}")
    private String videoBucket;

    @Value("${minio.video-cover}")
    private String videoCover;

    @Autowired
    private VideoUtil videoUtil;

    @Autowired
    private VideoIndexRepository videoIndexRepository;

    @Autowired
    private VideoEntityRepository videoEntityRepository;

    public String uploadAvatar(MultipartFile file) {
        return uploadFile(avatarBucket, file);
    }

    public String uploadCover(MultipartFile file) {
        return uploadFile(videoCover, file);
    }

    private String uploadFile(String bucket, MultipartFile file) {
        File tmpPath = saveFile(file, uploadTmp);
        if (tmpPath == null) {
            return null;
        }

        try {
            return minioUtil.upload(tmpPath, bucket);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            tmpPath.delete();
        }
    }

    @Transactional
    public String uploadVideo(MultipartFile file) {
        File tmpPath = saveFile(file, uploadTmp);
        if (tmpPath == null) {
            return null;
        }

        List<File> fileList;
        try {
            fileList = videoUtil.encodeVideoToM3u8AndTs(tmpPath);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            tmpPath.delete();
        }

        AtomicInteger videoDuration = new AtomicInteger();
        List<String> uploadList;
        try {
            uploadList = minioUtil.upload(fileList, videoBucket);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            fileList.forEach(f -> {
                if (f.getName().endsWith("m3u8")) {
                    videoDuration.set(minioUtil.getVideoDurationByM3u8(f));
                }
                f.delete();
            });
            fileList.get(0).getParentFile().delete();
        }

        String m3u8Url = uploadList.get(0);
        Assert.isTrue(m3u8Url.endsWith("m3u8"), "not m3u8 first");
        VideoIndex videoIndex = new VideoIndex();
        videoIndex.setM3u8Url(m3u8Url);
        videoIndex.setDuration(videoDuration.get());
        videoIndex.setVideoOriginName(m3u8Url.split("/")[m3u8Url.split("/").length - 1]);
        videoIndexRepository.save(videoIndex);
        uploadList.remove(0);

        List<VideoEntity> videoEntityList = new ArrayList<>();
        for (String tsUrl : uploadList) {
            VideoEntity tmp = new VideoEntity();
            tmp.setTsUrl(tsUrl);
            tmp.setVideoTsOriginName(tsUrl.split("/")[tsUrl.split("/").length - 1]);
            tmp.setVideoIndex(videoIndex);
            videoEntityList.add(tmp);
        }
        videoEntityRepository.saveAll(videoEntityList);

        return videoIndex.getM3u8Url();
    }

    public void releaseCover(String name) {
        release(videoCover, name);
    }

    public void releaseAvatar(String name) {
        release(avatarBucket, name);
    }

    public void releaseVideo(String name) {
        release(videoBucket, name);
    }

    public void releaseVideo(List<String> names) {
        for (String name : names) {
            releaseVideo(name);
        }
    }

    private void release(String bucket, String name) {
        minioUtil.delete(bucket, name);
    }

    @Transactional
    public void releaseVideo(Long id) {
        VideoIndex videoIndex = videoIndexRepository.findById(id).orElse(null);
        if (videoIndex == null) {
            return;
        }

        List<String> tsFiles = new ArrayList<>();
        for (VideoEntity videoEntity : videoIndex.getVideoEntityList()) {
            tsFiles.add(videoEntity.getVideoTsOriginName());
        }
        minioUtil.delete(videoBucket, tsFiles);
        minioUtil.delete(videoBucket, videoIndex.getVideoOriginName());

        videoIndexRepository.delete(videoIndex);
    }

    private File saveFile(MultipartFile file, String parentDir) {
        String fileName = UUID.randomUUID().toString().replace("-", "") + file.getOriginalFilename();
        File localFile = new File(parentDir + File.separator + fileName);
        try {
            file.transferTo(localFile);
        } catch (IOException e) {
            return null;
        }

        return localFile;
    }
}
